#include <Kharlia/Engine/Common.h>
#include <Kharlia/Engine/Init.h>
#include <Kharlia/Engine/Actor.h>

namespace kharlia { namespace engine {

void _InitActorBindings() {
    enum_<EDirection>("EDirection")
        .value("DIR_NORTH", DIR_NORTH)
        .value("DIR_WEST", DIR_WEST)
        .value("DIR_SOUTH", DIR_SOUTH)
        .value("DIR_EAST", DIR_EAST)
        .export_values()
        ;

    enum_<ENetRole>("ENetRole")
        .value("ROLE_NONE", ROLE_NONE)
        .value("ROLE_SIM_PROXY", ROLE_SIM_PROXY)
        .value("ROLE_AUTO_PROXY", ROLE_AUTO_PROXY)
        .value("ROLE_AUTHORITY", ROLE_AUTHORITY)
        .export_values()
        ;

    enum_<EActorRenderType>("EActorRenderType")
        .value("ART_NONE", ART_NONE)
        .value("ART_IMAGE", ART_IMAGE)
        .value("ART_ANI", ART_ANI)
        ;

    // NEW STUFF

    class_<AComponent, shared_ptr<AComponent>, bases<core::CObject>, noncopyable>
        ("AComponentBase", init<>())
        .def_readonly("Owner", &AComponent::mOwner)
        .def_readwrite("_Owner", &AComponent::mOwner)
        .def_readonly("Level", &AComponent::mLevel)
        .def_readwrite("_Level", &AComponent::mLevel)
        .def_readonly("NoDelete", &AComponent::mNoDelete)
        .def_readwrite("_NoDelete", &AComponent::mNoDelete)
        .def_readonly("Priority", &AComponent::mPriority)
        .def_readwrite("_Priority", &AComponent::mPriority)
        .add_property("Inited", &AComponent::GetInited)
        .def(self < self)
        .def("OnInit", &AComponent::_OnInit)
        .def("OnExit", &AComponent::_OnExit)
        .def("SendMsgArgs", pure_virtual(&AComponent::_SendEventArgs))
        .def("SendGameStarted", &AComponent::SendGameStarted)
        .def("SendGameStopped", &AComponent::SendGameStopped)
        .def("OnRecvGameStarted", &AComponent::_OnRecvGameStarted)
        .def("OnRecvGameStopped", &AComponent::_OnRecvGameStopped)
        //.def("CreateEventTasklet",
        //     (object (AComponent::*)(const object&, uint8, const object&))&AComponent::CreateEventTasklet,
        //     (arg("name"), arg("group")=core::CTasker::CURRENT_GROUP, arg("args")=make_tuple()))
        ;

    KH_IMPL_GC(AComponent);

    class_<ATransform, shared_ptr<ATransform>, bases<AComponent>, noncopyable>
        ("ATransformBase", init<>())
        .add_property("Position", make_getter(&ATransform::mPosition), &ATransform::SetPosition)
        .def("AddPosition", &ATransform::AddPosition)
        .def("Move", &ATransform::Move)
        .enable_pickling()
        ;

    class_<AMovement, shared_ptr<AMovement>, bases<AComponent>, noncopyable>
        ("AMovementBase", init<>())
        .def("OnInit", &AMovement::_OnInit)
        .def("OnExit", &AMovement::_OnExit)
        .add_property("Velocity", make_getter(&AMovement::mVelocity), &AMovement::SetVelocity)
        .add_property("Acceleration", make_getter(&AMovement::mAcceleration), &AMovement::SetAcceleration)
        .add_property("MaxVelocity", make_getter(&AMovement::mMaxVelocity), &AMovement::SetMaxVelocity)
        .add_property("MaxAcceleration", make_getter(&AMovement::mMaxAcceleration), &AMovement::SetMaxAcceleration)
        .def_readonly("Transform", &AMovement::mTransform)
        .def_readwrite("_Transform", &AMovement::mTransform)
        .enable_pickling()
        ;

    class_<ARender, shared_ptr<ARender>, bases<AComponent>, noncopyable>
        ("ARenderBase", init<>())
        .def("OnInit", &ARender::_OnInit)
        .def("OnExit", &ARender::_OnExit)
        .add_property("RenderType", make_getter(&ARender::mRenderType), &ARender::SetRenderType)
        .add_property("Direction", make_getter(&ARender::mDirection), &ARender::SetDirection)
        .add_property("Hidden", make_getter(&ARender::mHidden), &ARender::SetHidden)
        .def_readonly("Transform", &ARender::mTransform)
        .def_readwrite("_Transform", &ARender::mTransform)
        .enable_pickling()
        ;

    class_<APhysics, shared_ptr<APhysics>, bases<AComponent>, noncopyable>
        ("APhysicsBase", init<>())
        .def("OnInit", &APhysics::_OnInit)
        .def("OnExit", &APhysics::_OnExit)
        .add_property("Bounds", make_getter(&APhysics::mBounds), &APhysics::SetBounds)
        .add_property("CollideActors", &APhysics::GetCollideActors, &APhysics::SetCollideActors)
        .add_property("CollideTiles", &APhysics::GetCollideTiles, &APhysics::SetCollideTiles)
        .add_property("CollisionLayer", &APhysics::GetCollisionLayer, &APhysics::SetCollisionLayer)
        .def_readonly("Transform", &APhysics::mTransform)
        .def_readwrite("_Transform", &APhysics::mTransform)
        .def("OnTouched", pure_virtual(&APhysics::_OnTouched))
        .enable_pickling()
        ;
    
    class_<ACamera, shared_ptr<ACamera>, bases<AComponent>, noncopyable>
        ("ACameraBase", init<>())
        .def("OnInit", &ACamera::_OnInit)
        .def("OnExit", &ACamera::_OnExit)
        .add_property("Target", make_getter(&ACamera::mTarget), &ACamera::SetTarget)
        .add_property("TargetOffset", make_getter(&ACamera::mTargetOffset), &ACamera::SetTargetOffset)
        .enable_pickling()
        ;

    KH_IMPL_GC(ACamera);
    
    class_<AController, shared_ptr<AController>, bases<AComponent>, noncopyable>
        ("AControllerBase", init<>())
        .def("OnInit", &AController::_OnInit)
        .def("OnExit", &AController::_OnExit)
        .def_readonly("Pawn", &AController::mPawn)
        .def_readwrite("_Pawn", &AController::mPawn)
        .def("Possess", pure_virtual(&AController::_Possess))
        .def("Unpossess", pure_virtual(&AController::_Unpossess))
        .enable_pickling()
        ;

    KH_IMPL_GC(AController);
    
    class_<APlayerController, shared_ptr<APlayerController>, bases<AController>, noncopyable>
        ("APlayerControllerBase", init<>())
        .def("OnInit", &APlayerController::_OnInit)
        .def("OnExit", &APlayerController::_OnExit)
        .def_readwrite("Player", &APlayerController::mPlayer)
        .add_property("Camera", make_getter(&APlayerController::mCamera), &APlayerController::SetCamera)
        .enable_pickling()
        ;

    KH_IMPL_GC(APlayerController);
    
    class_<APawn, shared_ptr<APawn>, bases<AComponent>, noncopyable>
        ("APawnBase", init<>())
        .def("OnInit", &APawn::_OnInit)
        .def("OnExit", &APawn::_OnExit)
        .def_readonly("Controller", &APawn::mController)
        .def_readwrite("_Controller", &APawn::mController)
        .def("OnPossessed", pure_virtual(&APawn::_OnPossessed))
        .def("OnUnpossessed", pure_virtual(&APawn::_OnUnpossessed))
        .enable_pickling()
        ;

    KH_IMPL_GC(APawn);

    class_<ANetwork, shared_ptr<ANetwork>, bases<AComponent>, noncopyable>
        ("ANetworkBase", init<>())
        .def("OnInit", &ANetwork::_OnInit)
        .def("OnExit", &ANetwork::_OnExit)
        .def_readwrite("UseNativeRep", &ANetwork::mUseNativeRep)
        .def_readwrite("UsePythonRep", &ANetwork::mUsePythonRep)
        .def_readonly("HasNativeRep", &ANetwork::mHasNativeRep)
        .def_readonly("HasPythonRep", &ANetwork::mHasPythonRep)
        .def_readwrite("_HasPythonRep", &ANetwork::mHasPythonRep)
        .def_readwrite("Role", &ANetwork::mRole)
        .def_readwrite("RemoteRole", &ANetwork::mRemoteRole)
        ;

#define EXP_SLOT(TYPE) .add_property(#TYPE, make_function(&CActor::Get##TYPE, return_value_policy<copy_const_reference>()))

    class_<CActor, shared_ptr<CActor>, bases<core::CObject>, noncopyable>
        ("CActorBase", init<>())
        .def_readonly("ID", &CActor::mID)
        .def_readwrite("Tag", &CActor::mTag)
        .def_readonly("Level", &CActor::mLevel)
        .add_property("Owner", make_getter(&CActor::mOwner), &CActor::SetOwner)
        .add_property("NoDelete", &CActor::GetNoDelete)
        .def_readonly("DeleteMe", &CActor::mDeleteMe)
        EXP_SLOT(Transform)
        EXP_SLOT(Movement)
        EXP_SLOT(Render)
        EXP_SLOT(Physics)
        EXP_SLOT(Camera)
        EXP_SLOT(Pawn)
        EXP_SLOT(PlayerController)
        .def("GetComponent", (shared_ptr<AComponent> (CActor::*)(object) const)&CActor::GetComponent)
        .def("GetComponentExact", (shared_ptr<AComponent> (CActor::*)(object) const)&CActor::GetComponentExact)
        .def("AddComponent", &CActor::AddComponent)
        .def("RemoveComponent", &CActor::RemoveComponent)
        .def("OnCreated", &CActor::_OnCreated)
        .def("OnDestroyed", &CActor::_OnDestroyed)
        .def("OnGameStarted", &CActor::_OnGameStarted)
        .def("OnGameStopped", &CActor::_OnGameStopped)
        .def("__len__", &CActor::GetComponentCount)
        .def("__getitem__", (shared_ptr<AComponent> (CActor::*)(int) const)&CActor::GetComponent)
        .def_pickle(PSCActor())
        ;

    KH_IMPL_GC(CActor);
}

}}